#include "stm32f10x.h"                  // Device header
#include "I2C_Soft.h"
#include "MPU6050.h"

#define MPU6050_ADDRESS 0xd0

void MPU6050_WaitEvent(I2C_TypeDef* I2Cx,u32 I2C_EVENT)
{
	int Timeout = 10000;
	while(
		I2C_CheckEvent(I2Cx,I2C_EVENT) != SUCCESS
		&&
		Timeout-- > 0
	); //超时等待
}

void MPU6050_InitI2CPeriph(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; //复用开漏输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitStructure);
	
	I2C_InitTypeDef I2C_InitStructure;
	I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
	I2C_InitStructure.I2C_ClockSpeed = 50000;
	I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;//高速模式下占空比为2:1
	I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;//默认给应答
	I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;//当stm32作为从机时使用7位地址
	I2C_InitStructure.I2C_OwnAddress1 = 0x00;//若stm32作为从机时的地址
	I2C_Init(I2C2,&I2C_InitStructure);
	
	I2C_Cmd(I2C2,ENABLE);
}

void MPU6050_Soft_WriteRegister(u8 RegAddr,u8 Data)
{
	I2C_Soft_Start();
	I2C_Soft_SendByte(MPU6050_ADDRESS); //1101 000 0
	I2C_Soft_ReceiveAck();
	I2C_Soft_SendByte(RegAddr);
	I2C_Soft_ReceiveAck();
	I2C_Soft_SendByte(Data);
	I2C_Soft_ReceiveAck();
	I2C_Soft_Stop();
}

void MPU6050_WriteRegister(u8 RegAddr,u8 Data)
{
	I2C_GenerateSTART(I2C2,ENABLE);
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT);//EV5事件，起始条件已发送
	I2C_Send7bitAddress(I2C2,MPU6050_ADDRESS,I2C_Direction_Transmitter);
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);//EV6事件，地址已发送并接收到应答
	I2C_SendData(I2C2,RegAddr);
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTING);//EV8事件，字节已转入移位寄存器，数据寄存器DR为空并等待新的数据写入
	I2C_SendData(I2C2,Data);
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED);//EV8_2事件，移位寄存器已发完且DR也为空
	I2C_GenerateSTOP(I2C2,ENABLE);
	
}

u8 MPU6050_Soft_ReadRegister(u8 RegAddr)
{
	u8 data;
	I2C_Soft_Start();
	I2C_Soft_SendByte(MPU6050_ADDRESS); //1101 000 0
	I2C_Soft_ReceiveAck();
	I2C_Soft_SendByte(RegAddr);
	I2C_Soft_ReceiveAck(); //指定当前寄存读写指针
	
	I2C_Soft_Start(); //重复start
	I2C_Soft_SendByte(MPU6050_ADDRESS | 0x01); //1101 000 1
	I2C_Soft_ReceiveAck();
	data = I2C_Soft_ReceiveByte();
	I2C_Soft_SendAck(1); //不想继续读了就给非应答
	I2C_Soft_Stop();
	return data;
}

u8 MPU6050_ReadRegister(u8 RegAddr)
{
	u8 data;
	I2C_GenerateSTART(I2C2,ENABLE);
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT);//EV5事件，起始条件已发送
	I2C_Send7bitAddress(I2C2,MPU6050_ADDRESS,I2C_Direction_Transmitter);
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);//EV6事件，地址已发送并接收到应答
	I2C_SendData(I2C2,RegAddr);
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_TRANSMITTED);//EV8_2事件，移位寄存器已发完且DR也为空
	I2C_GenerateSTART(I2C2,ENABLE);
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_MODE_SELECT);//EV5事件，起始条件已发送
	I2C_Send7bitAddress(I2C2,MPU6050_ADDRESS,I2C_Direction_Receiver);
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED);//EV6事件，地址已发送并接收到应答
	
	I2C_AcknowledgeConfig(I2C2,DISABLE);//接收最后一个字节之前，要提前设置非应答和停止
	I2C_GenerateSTOP(I2C2,ENABLE);
	MPU6050_WaitEvent(I2C2,I2C_EVENT_MASTER_BYTE_RECEIVED);//EV8_2事件，移位寄存器已发完且DR也为空
	data = I2C_ReceiveData(I2C2);
	
	I2C_AcknowledgeConfig(I2C2,ENABLE);
	return data;
}

void MPU6050_Init(void)
{
	//I2C_Soft_Init();
	MPU6050_InitI2CPeriph();
	MPU6050_WriteRegister(MPU6050_PWR_MGMT_1,0x01);
	MPU6050_WriteRegister(MPU6050_PWR_MGMT_2,0x00); //6个轴均不待机
	MPU6050_WriteRegister(MPU6050_SMPLRT_DIV,0x09); //10分频
	MPU6050_WriteRegister(MPU6050_CONFIG,0x06);
	MPU6050_WriteRegister(MPU6050_GYRO_CONFIG,0x18);
	MPU6050_WriteRegister(MPU6050_ACCEL_CONFIG,0x18);//满量程
}

MPU6050_Data MPU6050_GetData(void)
{
	MPU6050_Data data;
	data.AccX = MPU6050_ReadRegister(MPU6050_ACCEL_XOUT_H)<<8 | MPU6050_ReadRegister(MPU6050_ACCEL_XOUT_L);
	data.AccY = MPU6050_ReadRegister(MPU6050_ACCEL_YOUT_H)<<8 | MPU6050_ReadRegister(MPU6050_ACCEL_YOUT_L);
	data.AccZ = MPU6050_ReadRegister(MPU6050_ACCEL_ZOUT_H)<<8 | MPU6050_ReadRegister(MPU6050_ACCEL_ZOUT_L);
	data.GyroX = MPU6050_ReadRegister(MPU6050_GYRO_XOUT_H)<<8 | MPU6050_ReadRegister(MPU6050_GYRO_XOUT_L);
	data.GyroY = MPU6050_ReadRegister(MPU6050_GYRO_YOUT_H)<<8 | MPU6050_ReadRegister(MPU6050_GYRO_YOUT_L);
	data.GyroZ = MPU6050_ReadRegister(MPU6050_GYRO_ZOUT_H)<<8 | MPU6050_ReadRegister(MPU6050_GYRO_ZOUT_L);
	return data;
}
